package cn.jltx.support;

import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.FragmentTransactionBugFixHack;
import android.view.View;
import android.view.ViewGroup;

import java.util.List;

import cn.jltx.constant.FragmentConstant;
import cn.jltx.utils.XqLog;

import static cn.jltx.constant.FragmentConstant.FRAGMENTATION_ARG_CONTAINER;
import static cn.jltx.constant.FragmentConstant.FRAGMENTATION_ARG_IS_ROOT;

/**
 * @author jltxseo
 *         Created by junlintianxia on 2017/04/14.
 */

public class FragmentImpl {

    public final String TAG = "FragmentImpl";

    private SupportAppCompatActivity mActivity;
    private long mShareElementDebounceTime; //用于出栈的时候给予一定的

    private static final long BUFFER_TIME = 50L;

    private Handler mHandler;
    private FragmentManager mPopToTempFragmentManager; //用于popFragmentTo的时候，当前页面销毁传入的FragmentManager为null而导致不能再继续执行afterPopTransactionRunnable的东西

    protected void attachActivity(SupportAppCompatActivity mActivity) {
        this.mActivity = mActivity;
        mHandler = new Handler(Looper.getMainLooper());
    }

    /**
     * 从栈顶开始查找,状态为show & userVisible的Fragment
     */
    public SupportFragment getActiveFragment(SupportFragment parentFragment, FragmentManager fragmentManager) {
        List<Fragment> fragmentList = fragmentManager.getFragments();
        if (fragmentList == null) {
            return parentFragment;
        }
        for (int i = fragmentList.size() - 1; i >= 0; i--) {
            Fragment fragment = fragmentList.get(i);
            if (fragment instanceof SupportFragment) {
                SupportFragment supportFragment = (SupportFragment) fragment;
                if (supportFragment.isResumed() && !supportFragment.isHidden() && supportFragment.getUserVisibleHint()) {
                    return getActiveFragment(supportFragment, supportFragment.getChildFragmentManager());
                }
            }
        }
        return parentFragment;
    }

    /**
     * 加载根Fragment, 即Activity内的第一个Fragment 或 Fragment内的第一个子Fragment
     *
     * @param containerId 容器id
     * @param to          目标Fragment
     */
    public void loadRootFragment(FragmentManager fragmentManager, int containerId, SupportFragment to) {
        bindContainerId(containerId, to);
        dispatchStartTransaction(fragmentManager, null, to, FragmentConstant.TYPE_ADD);
//        fragmentManager = checkFragmentManager(fragmentManager, null);
//        if (fragmentManager == null) return;
//
//        checkNotNull(to, "toFragment == null");
//        FragmentTransaction ft = fragmentManager.beginTransaction();
//
//        Bundle bundle = to.getArguments();
//        String toFragmentTag = to.getClass().getName();
//        ft.add(bundle.getInt(FragmentConstant.FRAGMENTATION_ARG_CONTAINER), to, toFragmentTag);
//        bundle.putBoolean(FragmentConstant.FRAGMENTATION_ARG_IS_ROOT, true);
//        ft.addToBackStack(toFragmentTag);
//        //提交添加事物
//        supportCommit(fragmentManager,ft);
    }


    public void loadMutipleRootFragment(FragmentManager fragmentManager, int containerId, int showPosition, SupportFragment... tos) {
        fragmentManager = checkFragmentManager(fragmentManager, null);
        if (fragmentManager == null) return;
        if (tos.length == 0) return;
        FragmentTransaction ft = fragmentManager.beginTransaction();
        for (int i = 0; i < tos.length; i++) {
            SupportFragment to = tos[i];
            bindContainerId(containerId, to);

            Bundle bundle = to.getArguments();
            bundle.putBoolean(FRAGMENTATION_ARG_IS_ROOT, true);
            String toNameTag = to.getClass().getName();

            ft.add(containerId, to, toNameTag);

            if (showPosition != i) {
                ft.hide(to);
            }
        }

        supportCommit(fragmentManager, ft);
    }

    /**
     * 将containterId和SupportFragment绑定
     *
     * @param containerId
     * @param to
     */
    private void bindContainerId(int containerId, SupportFragment to) {
        Bundle args = to.getArguments();
        if (args == null) {
            args = new Bundle();
            to.setArguments(args);
        }
        args.putInt(FRAGMENTATION_ARG_CONTAINER, containerId);
    }

    private FragmentManager checkFragmentManager(FragmentManager fragmentManager, Fragment from) {
        if (fragmentManager == null) {
            if (mPopToTempFragmentManager == null) {
                String fromName = from == null ? "Fragment" : from.getClass().getSimpleName();
                XqLog.e(TAG, fromName + "'s FragmentManager is null, " + " Please check if " + fromName + " is destroyed!");
                return null;
            }
            return mPopToTempFragmentManager;
        }
        return fragmentManager;
    }

    static <T> T checkNotNull(T value, String message) {
        if (value == null) {
            throw new NullPointerException(message);
        }
        return value;
    }

    private void supportCommit(FragmentManager fragmentManager, FragmentTransaction transaction) {
        boolean stateSaved = FragmentTransactionBugFixHack.isStateSaved(fragmentManager);
        if (stateSaved) {
            // 这里的警告请重视，请在Activity回来后，在onPostResume()中执行该事务
            XqLog.e(TAG, "Please beginTransaction in onPostResume() after the Activity returns!");
            IllegalStateException e = new IllegalStateException("Can not perform this action after onSaveInstanceState!");
            e.printStackTrace();
            mActivity.onExceptionAfterOnSaveInstanceState(e);
        }
        transaction.commitAllowingStateLoss();
    }

    /**
     * @param fragmentManager
     * @param from
     * @param to
     */
    public void dispatchStartTransaction(FragmentManager fragmentManager, SupportFragment from, SupportFragment to, int type) {
        fragmentManager = checkFragmentManager(fragmentManager, from);
        if (fragmentManager == null) return;

        if (from != null && from.isRemoving()) {
            XqLog.e(TAG, from.getClass().getSimpleName() + " is poped, maybe you want to call startWithPop()!");
        }

        checkNotNull(to, "toFragment == null");

        if (from != null) {
            //给要跳转的Fragment绑定id
            bindContainerId(from.getContainerId(), to);
        }

        String toFragmentTag = to.getClass().getName();

        switch (type) {
            case FragmentConstant.TYPE_ADD:
            case FragmentConstant.TYPE_ADD_RESULT:
                startFragment(fragmentManager, from, to, toFragmentTag);
                break;
            case FragmentConstant.TYPE_ADD_WITH_POP:
                startFragmentWithPop(fragmentManager, from, to, toFragmentTag);
                break;

        }
    }

    /**
     * @param fragmentManager
     * @param from
     * @param to
     * @param toFragmentTag
     */
    protected void startFragment(FragmentManager fragmentManager, SupportFragment from, SupportFragment to, String toFragmentTag) {
        FragmentTransaction ft = fragmentManager.beginTransaction();

        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);

        if (from == null) {
            Bundle bundle = to.getArguments();
            ft.add(bundle.getInt(FRAGMENTATION_ARG_CONTAINER), to, toFragmentTag);
            bundle.putBoolean(FRAGMENTATION_ARG_IS_ROOT, true);
        } else {
            ft.add(from.getContainerId(), to, toFragmentTag);
            if (from.getTag() != null) {
                ft.hide(from);
            }
        }

        ft.addToBackStack(toFragmentTag);
        supportCommit(fragmentManager, ft);
    }

    /**
     * @param fragmentManager
     * @param from
     * @param to
     * @param toFragmentTag
     */
    protected void startFragmentWithPop(FragmentManager fragmentManager, SupportFragment from, SupportFragment to, String toFragmentTag) {
        fragmentManager.executePendingTransactions(); //让fragmentManager立即执行未执行的事务
        if (from.isHidden()) {
            XqLog.e(TAG, from.getClass().getSimpleName() + " is hidden, " + "the transaction of startWithPop() is invalid!");
            return;
        }
        //获取当前Fragment的上一个Fragment
        SupportFragment preFragment = getPreFragment(from);
        handlePopAnim(preFragment, from, to);

        FragmentTransaction ft = fragmentManager.beginTransaction();
        if (!from.isIsRoot()) {
            FragmentTransaction removeFt = fragmentManager.beginTransaction().remove(from);
            supportCommit(fragmentManager, removeFt);
            debouncePop(from, fragmentManager);

            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
                    .add(from.getContainerId(), to, toFragmentTag)
                    .addToBackStack(toFragmentTag);

            if (preFragment != null) {
                ft.hide(preFragment);
            }

        } else {

            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
                    .add(from.getContainerId(), to, toFragmentTag)
                    .addToBackStack(toFragmentTag);

            if (preFragment != null) {
                ft.hide(preFragment);
            }

            if (from.getTag() != null) {
                ft.hide(from);
            }
        }

        supportCommit(fragmentManager, ft);
        fragmentManager.executePendingTransactions();
    }

    /**
     * @param fragmentTag
     * @param includeSelf
     * @param afterPopTransactionRunnable
     * @param fragmentManager
     */
    public void popFragmentTo(String fragmentTag, boolean includeSelf, Runnable afterPopTransactionRunnable, FragmentManager fragmentManager) {
        fragmentManager = checkFragmentManager(fragmentManager, null);
        if (fragmentManager == null) return;

        Fragment targetFragment = fragmentManager.findFragmentByTag(fragmentTag);

        //没有找到要出栈的目标Fragment
        if (targetFragment == null) {
            XqLog.e(TAG, "Pop failure! Can't find FragmmenTag:" + fragmentTag);
            return;
        }

        int flag = 0;
        if (includeSelf) {
            flag = FragmentManager.POP_BACK_STACK_INCLUSIVE;
            targetFragment = getPreFragment(targetFragment);
        }

        SupportFragment fromFragment = getTopFragment(fragmentManager);

        if (afterPopTransactionRunnable != null) {
            if (targetFragment != fromFragment) {
                handlePopAnim(targetFragment, fromFragment, null);
            }

            popToFix(fragmentManager, fragmentTag, flag);
            final FragmentManager finalFragmentManager = fragmentManager;
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mPopToTempFragmentManager = finalFragmentManager;
                }
            });
            mHandler.post(afterPopTransactionRunnable);
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mPopToTempFragmentManager = null;
                }
            });
        } else {
            popToFix(fragmentManager, fragmentTag, flag);
        }

    }

    /**
     * 分发回退事件, 优先栈顶(有子栈则是子栈的栈顶)的Fragment
     */
    public boolean dispatchBackPressedEvent(SupportFragment activeFragment) {
        if (activeFragment != null) {
            boolean result = activeFragment.onBackPressedSupport();
            if (result) {
                return true;
            }

            Fragment parentFragment = activeFragment.getParentFragment();
            if (dispatchBackPressedEvent((SupportFragment) parentFragment)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 出栈
     *
     * @param fragmentManager
     */
    void back(FragmentManager fragmentManager) {
        fragmentManager = checkFragmentManager(fragmentManager, null);
        if (fragmentManager == null) return;

        int count = fragmentManager.getBackStackEntryCount();
        if (count > 0) {
            debouncePop(null, fragmentManager);
        }
    }

    /**
     * 出栈到上一个页面
     *
     * @param from
     * @param fragmentManager
     */
    private void debouncePop(SupportFragment from, FragmentManager fragmentManager) {
        // Debounce
        if (from == null) {
            from = getTopFragment(fragmentManager);
        }
        long now = System.currentTimeMillis();
        if (now < mShareElementDebounceTime) {
            XqLog.d(TAG, "debouncePop出栈中..."); //防止返回按钮抖动
            return;
        }
        mShareElementDebounceTime = System.currentTimeMillis() + from.getExitAnimDuration();

        fragmentManager.popBackStackImmediate();
    }

    private void popToFix(final FragmentManager fragmentManager, String fragmentTag, int flag) {
        if (fragmentManager.getFragments() == null) return;

        mActivity.preparePopMultiple();
        fragmentManager.popBackStackImmediate(fragmentTag, flag);
        mActivity.popFinish();

        mHandler.post(new Runnable() {
            @Override
            public void run() {
                FragmentTransactionBugFixHack.reorderIndices(fragmentManager);
            }
        });

    }

    /**
     * 处理出栈当前Fragment接着打开新Fragment的动画
     *
     * @param preFragment  前一个Fragment
     * @param fromFragment 当前Fragment
     * @param toFragment   即将要跳转的Fragment
     */
    private void handlePopAnim(Fragment preFragment, SupportFragment fromFragment, SupportFragment toFragment) {
        if (preFragment == null) return;

        View preView = preFragment.getView();
        if (preView == null || !(preView instanceof ViewGroup)) return;
        ViewGroup preViewGroup = (ViewGroup) preView;

        final View fromView = fromFragment.getView();
        if (fromView == null) return;

        // 不调用 会闪屏
        preViewGroup.setVisibility(View.VISIBLE);
        try {
            ViewGroup container = (ViewGroup) mActivity.findViewById(fromFragment.getContainerId());
            if (container != null) {
                container.removeView(fromView);
                if (fromFragment.getSaveInstanceState() != null && toFragment != null) {
                    preViewGroup = container;
                }

                if (fromView.getLayoutParams().height != ViewGroup.LayoutParams.MATCH_PARENT) {
                    fromView.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
                }

                //截图
                Bitmap bitmap = capterBitmap(fromView);
                final Drawable drawable = new BitmapDrawable(preViewGroup.getResources(), bitmap);

                showHideChildView(preViewGroup, false);
                Drawable bg = preViewGroup.getBackground();
                preViewGroup.setBackgroundDrawable(drawable);
                restoreView(preViewGroup, bg, toFragment == null ? BUFFER_TIME : Math.max(fromFragment.getEnterAnimDuration(), fromFragment.getPopExitAnimDuration()) + BUFFER_TIME);
            }
        } catch (Exception e) {
            XqLog.e(TAG, "handlePopAnim erro" + e);
        }
    }

    /**
     * 截屏
     *
     * @param view
     * @return
     */
    private Bitmap capterBitmap(View view) {
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();  //启用DrawingCache并创建位图
        Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache()); //创建一个DrawingCache的拷贝，因为DrawingCache得到的位图在禁用后会被回收
        view.setDrawingCacheEnabled(false);  //禁用DrawingCahce否则会影响性能
        return bitmap;
    }


    private void restoreView(final ViewGroup viewGroup, final Drawable bgDrawable, long delay) {
        viewGroup.postDelayed(new Runnable() {
            @Override
            public void run() {
                viewGroup.setBackgroundDrawable(bgDrawable);
                showHideChildView(viewGroup, true);
            }
        }, delay);
    }

    private void showHideChildView(ViewGroup viewGroup, boolean show) {
        for (int i = 0; i < viewGroup.getChildCount(); i++) {
            View child = viewGroup.getChildAt(i);
            child.setVisibility(show ? View.VISIBLE : View.GONE);
        }
    }

    /**
     * 获取当前Fragment的前一个Fragment
     *
     * @param fragment
     * @return
     */
    protected SupportFragment getPreFragment(Fragment fragment) {
        FragmentManager fragmentManager = fragment.getFragmentManager();
        fragmentManager = checkFragmentManager(fragmentManager, fragment);
        if (fragmentManager != null) {
            List<Fragment> fragmentList = fragmentManager.getFragments();
            if (fragmentList == null) return null;

            int curIndex = fragmentList.indexOf(fragment);
            for (int i = curIndex - 1; i >= 0; i++) {
                Fragment preFragment = fragmentList.get(i);
                if (preFragment instanceof SupportFragment) {
                    return (SupportFragment) preFragment;
                }
            }
        }
        return null;
    }

    /**
     * 获得栈顶SupportFragment
     */
    protected SupportFragment getTopFragment(FragmentManager fragmentManager) {
        fragmentManager = checkFragmentManager(fragmentManager, null);
        if (fragmentManager == null) return null;
        List<Fragment> fragmentList = fragmentManager.getFragments();
        if (fragmentList == null) return null;

        for (int i = fragmentList.size() - 1; i >= 0; i--) {
            Fragment fragment = fragmentList.get(i);
            if (fragment instanceof SupportFragment) {
                return (SupportFragment) fragment;
            }
        }
        return null;
    }

    protected <T extends SupportFragment> T findStackFragment(FragmentManager fragmentManager, Class<T> fragmentClass, String toFragmentTag) {
        fragmentManager = checkFragmentManager(fragmentManager, null);
        if (fragmentManager == null) return null;
        Fragment fragment = null;
        if (toFragmentTag == null) {
            // 如果是 查找Fragment时,则有可能是在FragmentPagerAdapter/FragmentStatePagerAdapter中,这种情况下,
            // 它们的Tag是以android:switcher开头,所以这里我们使用下面的方式
            List<Fragment> fragments = fragmentManager.getFragments();
            if (fragments == null) return null;

            int sizeChildFrg = fragments.size();
            for (int i = sizeChildFrg - 1; i >= 0; i--) {
                Fragment brotherFragment = fragments.get(i);
                if (brotherFragment instanceof SupportFragment && brotherFragment.getClass().getName().equals(fragmentClass.getName())) {
                    fragment = brotherFragment;
                    break;
                }
            }
        } else {
            fragment = fragmentManager.findFragmentByTag(toFragmentTag);
        }

        if (fragment == null) {
            return null;
        }
        return (T) fragment;
    }

    /**
     * show一个Fragment,hide另一个／多个Fragment ; 主要用于类似微信主页那种 切换tab的情况
     * 一般配合loadMultipleRootFragment使用
     *
     * @param showFragment 需要show的Fragment
     * @param hideFragment 需要hide的Fragment
     */
    public void showHideFragment(FragmentManager fragmentManager, SupportFragment showFragment, SupportFragment hideFragment) {
        fragmentManager = checkFragmentManager(fragmentManager, null);
        if (null == fragmentManager) return;
        if (showFragment == hideFragment) return;
        checkNotNull(showFragment, "showFragment == null");

        FragmentTransaction ft = fragmentManager.beginTransaction().show(showFragment);
        if (hideFragment == null) {
            List<Fragment> fragmentList = fragmentManager.getFragments();
            if (fragmentList != null) {
                for (Fragment fragment : fragmentList) {
                    if (fragment != null && fragment != showFragment) {
                        ft.hide(fragment);
                    }
                }
            }
        } else {
            ft.hide(hideFragment);
        }
        supportCommit(fragmentManager, ft);
    }

    /**
     * replace分发load根Fragment事务
     *
     * @param containerId 容器id
     * @param to          目标Fragment
     */
    public void replaceLoadRootTransaction(FragmentManager fragmentManager, int containerId, SupportFragment to, boolean addToBack) {
        replaceTransaction(fragmentManager, containerId, to, addToBack);
    }

    /**
     * replace事务, 主要用于子Fragment之间的replace,主要用于类似京东这些应用商店那样直接替换内容页面
     * @param from
     * @param to
     * @param addToBack
     */
    public void replaceTransaction(SupportFragment from, SupportFragment to, boolean addToBack) {
        replaceTransaction(from.getFragmentManager(), from.getContainerId(), to, addToBack);
    }

    /**
     * replace事务, 主要用于子Fragment之间的replace,主要用于类似京东这些应用商店那样直接替换内容页面
     *
     * @param fragmentManager
     * @param containerId
     * @param to
     * @param addToBack
     */
    public void replaceTransaction(FragmentManager fragmentManager, int containerId, SupportFragment to, boolean addToBack) {
        fragmentManager = checkFragmentManager(fragmentManager, null);
        if (null == fragmentManager) return;
        checkNotNull(to, "toFragment == null");
        bindContainerId(containerId, to);
        FragmentTransaction ft = fragmentManager.beginTransaction();
        ft.replace(containerId, to, to.getClass().getName());
        if (addToBack) {
            ft.addToBackStack(to.getClass().getName());
        }

        Bundle bundle = to.getArguments();
        bundle.putBoolean(FRAGMENTATION_ARG_IS_ROOT, true);
        supportCommit(fragmentManager, ft);
    }


}
